/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.common.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @author vacoor
 */
public abstract class Reflections {

    /**
     * 如果 clazz 中 method 静态方法是有效的则调用
     *
     * @param clazz  方法定义类或其子类
     * @param method 静态方法名称
     * @param force  是否强制调用(忽略可见性)
     * @param args   调用参数
     * @param <R>    返回值类型
     * @return 方法返回值
     */
    public static <R> R invokeIfAvaliable(Class<?> clazz, String method, boolean force, Object... args) {
        return invokeIfAvaliable(clazz, null, method, force, args);
    }

    /**
     * 如果 target 中 method 方法是有效的则调用
     *
     * @param target 调用对象
     * @param method 方法名称
     * @param force  是否强制调用(忽略可见性)
     * @param args   调用参数
     * @param <R>    返回值类型
     * @return 方法返回值
     */
    public static <R> R invokeIfAvaliable(Object target, String method, boolean force, Object... args) {
        if (null == target) {
            return null;
        }
        return invokeIfAvaliable(target.getClass(), target, method, force, args);
    }

    /**
     * 如果 clazz 中 method 方法是有效的则调用
     *
     * @param clazz  方法定义类或其子类
     * @param target 调用对象
     * @param method 方法名称
     * @param force  是否强制调用(忽略可见性)
     * @param args   调用参数
     * @param <R>    返回值类型
     * @return 方法返回值
     */
    public static <R> R invokeIfAvaliable(Class<?> clazz, Object target, String method, boolean force, Object... args) {
        if (null == clazz) {
            return null;
        }

        Class<?>[] argsType = new Class<?>[args.length];
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            argsType[i] = null != arg ? arg.getClass() : null;
        }

        try {
            Method fn = MethodFinder.findMethod(clazz, force, method, argsType);
            if ((!fn.isAccessible() || !Modifier.isPublic(fn.getModifiers())) && force) {
                fn.setAccessible(true);
            }
            return (R) fn.invoke(target, args);
        } catch (NoSuchMethodException e) {
            // method not find
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void ensureAccessible(Field field) {
        if (!Modifier.isPublic(field.getModifiers())
                || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
                || !Modifier.isFinal(field.getModifiers())
                || !field.isAccessible()) {
            field.setAccessible(true);
        }
    }


    /**
     * 确保给定 method 对象可访问
     *
     * @param method
     */
    public static void ensureAccessible(Method method) {
        if (!Modifier.isPublic(method.getModifiers())
                || !Modifier.isPublic(method.getDeclaringClass().getModifiers())
                || !method.isAccessible()) {
            method.setAccessible(true);
        }
    }
}